import 'package:lib_base/data_repository/data_repository_interface.dart';
import 'package:lib_base/data_repository/data_repository_manager.dart';
import 'package:rxdart/subjects.dart';

abstract class ListDataRepository<T> extends DataRepositoryInterface {
  PublishSubject<List<T>?> dataObservable = PublishSubject();
  PublishSubject<T> itemObservable = PublishSubject();

  dynamic encode(T item);

  T? decode(dynamic item);

  List<T>? decodeList(dynamic data) {
    if (data != null && data is List<dynamic>) {
      List<T> values = [];
      for (var element in data) {
        T? value = decode(element);
        if (value != null) {
          values.add(value);
        }
      }
      return values;
    } else {
      return null;
    }
  }

  @override
  void onDataChanged(dynamic data) {
    dataObservable.add(decodeList(data));
  }

  @override
  void onItemChanged(dynamic item) {
    T? decodeItem = decode(item);
    if (decodeItem == null) {
      return;
    }

    itemObservable.add(decodeItem);
  }

  Future<List<T>?> getData() async {
    dynamic data = await DataRepositoryManager.instance.getData(id);
    return decodeList(data);
  }

  Future<bool?> setData(List<T>? value) async {
    return DataRepositoryManager.instance.setData(
        id, value != null ? List.from(value.map((e) => encode(e))) : null);
  }

  Future<bool?> updateItem(T item) async {
    return DataRepositoryManager.instance.updateItem(id, encode(item));
  }

  Future<bool?> updateItemValue(
      String itemId, String key, dynamic value) async {
    return DataRepositoryManager.instance
        .updateItemValue(id, itemId: itemId, key: key, value: value);
  }

  Future<bool?> addItem(T item) async {
    return DataRepositoryManager.instance.addItem(id, encode(item));
  }

  Future<bool?> insertItem(T item) async {
    return DataRepositoryManager.instance.insertItem(id, encode(item));
  }

  Future<T?> getItem(int index) async {
    dynamic item = await DataRepositoryManager.instance.getItem(id, index);

    if (item == null) {
      return null;
    }

    return decode(item);
  }

  Future<T?> getItemById(String itemId) async {
    dynamic item = await DataRepositoryManager.instance.getItemById(id, itemId);

    if (item == null) {
      return null;
    }

    return decode(item);
  }

  Future<bool?> removeItemById(String itemId) async {
    return DataRepositoryManager.instance.removeItemById(id, itemId);
  }
}
